8

ES6新增的class语法非常帅,但是围绕这个新的语法糖,在class中如何实现静态属性、私有属性、私有方法的问题,成为了大家探讨的话题。本文打算绕过现有的weakmap、symbol的方案,从最简单的实践中抽取出满足要求的方案。

静态属性

静态方法非常好实现,就是在普通方法名前面添加static关键字。那么静态属性呢?其实也可以通过static关键字来处理:

class MyClass {
    static get name() {
        return 'my name'
    }
}

这样就可以使用MyClass.name获取静态属性值了。而且因为没有设置setter,所以这个静态属性值还不能被改变。当然,你也可以把setter加上去。

私有属性

首先要搞明白“私有属性”意味着几层意思,不是说形式上满足需求就可以,而是要从代码的机理上实现“私有”效果:

1 class内部不同方法间可以使用,因此this要指向实例化对象(必须)
2 不能被外部访问,因此实例化对象person.name既不能获得值,也不能设定值,应该返回undefined,甚至应该在实例化之后,并不知道有name这个属性存在,开发者甚至可以自己再person.name = 'new name'动态去创建一个非私有属性(必须)
3 不能被继承,因此extends后子类不具备该属性(必须)
4 方便的调用方式,比如类this._name形式(备选)

上面这些应该是作为私有属性的主要条件,如果连这些都不满足,很难谈得上叫“私有属性”。

实现方法:

var attributions = {}
function get(that, key) {
    return attributions[that] && attributions[that][key]
}
function set(that, key, value) {
    if(!attributions[that]) attributions[that] = {}
    attributions[that][key] = value
}

class MyClass {
    set() {
        set(this, 'name', 'my name')
    }
    get() {
        let name = get(this, 'name')
        console.log(name)
    }
}

在类外面有一个辅助对象attributions,两个辅助函数set, get。它们将不被实例化对象直接访问,因此是一个相对封闭的空间,外部完全无法访问set, get函数操作的内容,但对于类的实例化对象而已,确实有自己对应的属性内容,因此,这种方案,可以代替类内部的私有属性的功能。

私有方法

理论上讲,私有属性和私有方法的区别是,私有方法是函数。因此,实际上,上面私有属性的实现过程中已经实现了私有方法,就是上面的set, get两个辅助函数,这两个函数帮助类完成一些操作,同时对于每一个实例化对象而言都可以设置对应的值,而且也不会被外部获取。

getter和setter的实现

现在很多类实现了getter和setter,将内部的数据管理和自身的属性分开,改变数据和改变属性是两回事。

var events = {}
var data = {}
class MyClass {
    on(event, handler) {
        if(!events[event]) events[event] = []
        events[event].push(handler)
    }
    trigger(event, params = []) {
        let evts = events[event]
        if(Array.isArray(evts)) evts.forEach(callback => {
            if(typeof callback === 'function') {
                if(Array.isArray(params)) callback.apply(this, params)
                else callback.call(this, params)
            }
        })
    }
    get(key) {
        return data[this] && data[this][key]
    }
    set(key, value, notify = true) {
        if(!data[this]) data[this] = {}
        data[this][key] = value
        if(notify) {
            this.trigger('change:' + key, value)
        }
    }
    call(factory, ...args) {
        factory.apply(this, args)
    }
}

上面的类中定义了我们最常用的on, trigger, get, set, call这几个方法。使用方法:

var a = new MyClass()
a.on('change:name', value => console.log(value))
a.set('name', 'my value')

这样不仅可以有效的管理组织自己的数据,而且还可以通过绑定,实现数据变化的监听。


求个兼职,如果您有web开发方面的需要,可以联系我,生活不容易,且行且珍惜。
我的个人博客 www.tangshuang.net 这里就不留信息了,请在博客留言,我会联系你


否子戈
2.2k 声望143 粉丝

疯狂前端开发中……